/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @format
 * @emails oncall+react_native
 */

'use strict';

const Easing = require('../Easing');
describe('Easing', () => {
  it('should work with linear', () => {
    const easing = Easing.linear;

    expect(easing(0)).toBe(0);
    expect(easing(0.5)).toBe(0.5);
    expect(easing(0.8)).toBe(0.8);
    expect(easing(1)).toBe(1);
  });

  it('should work with ease in linear', () => {
    const easing = Easing.in(Easing.linear);
    expect(easing(0)).toBe(0);
    expect(easing(0.5)).toBe(0.5);
    expect(easing(0.8)).toBe(0.8);
    expect(easing(1)).toBe(1);
  });

  it('should work with easy out linear', () => {
    const easing = Easing.out(Easing.linear);
    expect(easing(0)).toBe(0);
    expect(easing(0.5)).toBe(0.5);
    expect(easing(0.6)).toBe(0.6);
    expect(easing(1)).toBe(1);
  });

  it('should work with ease in quad', () => {
    function easeInQuad(t) {
      return t * t;
    }
    const easing = Easing.in(Easing.quad);
    for (let t = -0.5; t < 1.5; t += 0.1) {
      expect(easing(t)).toBe(easeInQuad(t));
    }
  });

  it('should work with ease out quad', () => {
    function easeOutQuad(t) {
      return -t * (t - 2);
    }
    const easing = Easing.out(Easing.quad);
    for (let t = 0; t <= 1; t += 0.1) {
      expect(easing(1)).toBe(easeOutQuad(1));
    }
  });

  it('should work with ease in-out quad', () => {
    function easeInOutQuad(t) {
      t = t * 2;
      if (t < 1) {
        return 0.5 * t * t;
      }
      return -((t - 1) * (t - 3) - 1) / 2;
    }
    const easing = Easing.inOut(Easing.quad);
    for (let t = -0.5; t < 1.5; t += 0.1) {
      expect(easing(t)).toBeCloseTo(easeInOutQuad(t), 4);
    }
  });

  it('should satisfy boundary conditions with elastic', () => {
    for (let b = 0; b < 4; b += 0.3) {
      const easing = Easing.elastic(b);
      expect(easing(0)).toBe(0);
      expect(easing(1)).toBe(1);
    }
  });

  function sampleEasingFunction(easing) {
    const DURATION = 300;
    const tickCount = Math.round((DURATION * 60) / 1000);
    const samples = [];
    for (let i = 0; i <= tickCount; i++) {
      samples.push(easing(i / tickCount));
    }
    return samples;
  }

  const Samples = {
    in_quad: [
      0,
      0.0030864197530864196,
      0.012345679012345678,
      0.027777777777777776,
      0.04938271604938271,
      0.0771604938271605,
      0.1111111111111111,
      0.15123456790123457,
      0.19753086419753085,
      0.25,
      0.308641975308642,
      0.37345679012345684,
      0.4444444444444444,
      0.5216049382716049,
      0.6049382716049383,
      0.6944444444444445,
      0.7901234567901234,
      0.8919753086419753,
      1,
    ],
    out_quad: [
      0,
      0.10802469135802469,
      0.20987654320987653,
      0.3055555555555555,
      0.3950617283950617,
      0.47839506172839513,
      0.5555555555555556,
      0.6265432098765432,
      0.691358024691358,
      0.75,
      0.8024691358024691,
      0.8487654320987654,
      0.888888888888889,
      0.9228395061728394,
      0.9506172839506174,
      0.9722222222222221,
      0.9876543209876543,
      0.9969135802469136,
      1,
    ],
    inOut_quad: [
      0,
      0.006172839506172839,
      0.024691358024691357,
      0.05555555555555555,
      0.09876543209876543,
      0.154320987654321,
      0.2222222222222222,
      0.30246913580246915,
      0.3950617283950617,
      0.5,
      0.6049382716049383,
      0.697530864197531,
      0.7777777777777777,
      0.845679012345679,
      0.9012345679012346,
      0.9444444444444444,
      0.9753086419753086,
      0.9938271604938271,
      1,
    ],
    in_cubic: [
      0,
      0.00017146776406035664,
      0.0013717421124828531,
      0.004629629629629629,
      0.010973936899862825,
      0.021433470507544586,
      0.037037037037037035,
      0.05881344307270234,
      0.0877914951989026,
      0.125,
      0.1714677640603567,
      0.22822359396433475,
      0.2962962962962963,
      0.37671467764060357,
      0.4705075445816187,
      0.5787037037037038,
      0.7023319615912208,
      0.8424211248285322,
      1,
    ],
    out_cubic: [
      0,
      0.15757887517146785,
      0.2976680384087792,
      0.42129629629629617,
      0.5294924554183813,
      0.6232853223593964,
      0.7037037037037036,
      0.7717764060356652,
      0.8285322359396433,
      0.875,
      0.9122085048010974,
      0.9411865569272977,
      0.9629629629629629,
      0.9785665294924554,
      0.9890260631001372,
      0.9953703703703703,
      0.9986282578875172,
      0.9998285322359396,
      1,
    ],
    inOut_cubic: [
      0,
      0.0006858710562414266,
      0.0054869684499314125,
      0.018518518518518517,
      0.0438957475994513,
      0.08573388203017834,
      0.14814814814814814,
      0.23525377229080935,
      0.3511659807956104,
      0.5,
      0.6488340192043895,
      0.7647462277091908,
      0.8518518518518519,
      0.9142661179698217,
      0.9561042524005487,
      0.9814814814814815,
      0.9945130315500685,
      0.9993141289437586,
      1,
    ],
    in_sin: [
      0,
      0.003805301908254455,
      0.01519224698779198,
      0.03407417371093169,
      0.06030737921409157,
      0.09369221296335006,
      0.1339745962155613,
      0.1808479557110082,
      0.233955556881022,
      0.2928932188134524,
      0.35721239031346064,
      0.42642356364895384,
      0.4999999999999999,
      0.5773817382593005,
      0.6579798566743311,
      0.7411809548974793,
      0.8263518223330696,
      0.9128442572523416,
      0.9999999999999999,
    ],
    out_sin: [
      0,
      0.08715574274765817,
      0.17364817766693033,
      0.25881904510252074,
      0.3420201433256687,
      0.42261826174069944,
      0.49999999999999994,
      0.573576436351046,
      0.6427876096865393,
      0.7071067811865475,
      0.766044443118978,
      0.8191520442889918,
      0.8660254037844386,
      0.9063077870366499,
      0.9396926207859083,
      0.9659258262890683,
      0.984807753012208,
      0.9961946980917455,
      1,
    ],
    inOut_sin: [
      0,
      0.00759612349389599,
      0.030153689607045786,
      0.06698729810778065,
      0.116977778440511,
      0.17860619515673032,
      0.24999999999999994,
      0.32898992833716556,
      0.4131759111665348,
      0.49999999999999994,
      0.5868240888334652,
      0.6710100716628343,
      0.7499999999999999,
      0.8213938048432696,
      0.883022221559489,
      0.9330127018922194,
      0.9698463103929542,
      0.9924038765061041,
      1,
    ],
    in_exp: [
      0,
      0.0014352875901128893,
      0.002109491677524035,
      0.0031003926796253885,
      0.004556754060844206,
      0.006697218616039631,
      0.009843133202303688,
      0.014466792379488908,
      0.021262343752724643,
      0.03125,
      0.045929202883612456,
      0.06750373368076916,
      0.09921256574801243,
      0.1458161299470146,
      0.2143109957132682,
      0.31498026247371835,
      0.46293735614364506,
      0.6803950000871883,
      1,
    ],
    out_exp: [
      0,
      0.31960499991281155,
      0.5370626438563548,
      0.6850197375262816,
      0.7856890042867318,
      0.8541838700529854,
      0.9007874342519875,
      0.9324962663192309,
      0.9540707971163875,
      0.96875,
      0.9787376562472754,
      0.9855332076205111,
      0.9901568667976963,
      0.9933027813839603,
      0.9954432459391558,
      0.9968996073203746,
      0.9978905083224759,
      0.9985647124098871,
      1,
    ],
    inOut_exp: [
      0,
      0.0010547458387620175,
      0.002278377030422103,
      0.004921566601151844,
      0.010631171876362321,
      0.022964601441806228,
      0.049606282874006216,
      0.1071554978566341,
      0.23146867807182253,
      0.5,
      0.7685313219281775,
      0.892844502143366,
      0.9503937171259937,
      0.9770353985581938,
      0.9893688281236377,
      0.9950784333988482,
      0.9977216229695779,
      0.998945254161238,
      1,
    ],
    in_circle: [
      0,
      0.0015444024660317135,
      0.006192010000093506,
      0.013986702816730645,
      0.025003956956430873,
      0.03935464078941209,
      0.057190958417936644,
      0.07871533601238889,
      0.10419358352238339,
      0.1339745962155614,
      0.1685205807169019,
      0.20845517506805522,
      0.2546440075000701,
      0.3083389112228482,
      0.37146063894529113,
      0.4472292016074334,
      0.5418771527091488,
      0.6713289009389102,
      1,
    ],
    out_circle: [
      0,
      0.3286710990610898,
      0.45812284729085123,
      0.5527707983925666,
      0.6285393610547089,
      0.6916610887771518,
      0.7453559924999298,
      0.7915448249319448,
      0.8314794192830981,
      0.8660254037844386,
      0.8958064164776166,
      0.9212846639876111,
      0.9428090415820634,
      0.9606453592105879,
      0.9749960430435691,
      0.9860132971832694,
      0.9938079899999065,
      0.9984555975339683,
      1,
    ],
    inOut_circle: [
      0,
      0.003096005000046753,
      0.012501978478215436,
      0.028595479208968322,
      0.052096791761191696,
      0.08426029035845095,
      0.12732200375003505,
      0.18573031947264557,
      0.2709385763545744,
      0.5,
      0.7290614236454256,
      0.8142696805273546,
      0.8726779962499649,
      0.915739709641549,
      0.9479032082388084,
      0.9714045207910317,
      0.9874980215217846,
      0.9969039949999532,
      1,
    ],
    in_back_: [
      0,
      -0.004788556241426612,
      -0.017301289437585736,
      -0.0347587962962963,
      -0.05438167352537723,
      -0.07339051783264748,
      -0.08900592592592595,
      -0.09844849451303156,
      -0.0989388203017833,
      -0.08769750000000004,
      -0.06194513031550073,
      -0.018902307956104283,
      0.044210370370370254,
      0.13017230795610413,
      0.2417629080932785,
      0.3817615740740742,
      0.5529477091906719,
      0.7581007167352535,
      0.9999999999999998,
    ],
    out_back_: [
      2.220446049250313e-16,
      0.24189928326474652,
      0.44705229080932807,
      0.6182384259259258,
      0.7582370919067215,
      0.8698276920438959,
      0.9557896296296297,
      1.0189023079561044,
      1.0619451303155008,
      1.0876975,
      1.0989388203017834,
      1.0984484945130315,
      1.089005925925926,
      1.0733905178326475,
      1.0543816735253773,
      1.0347587962962963,
      1.0173012894375857,
      1.0047885562414267,
      1,
    ],
  };

  Object.keys(Samples).forEach(function(type) {
    it('should ease ' + type, function() {
      const [modeName, easingName, isFunction] = type.split('_');
      let easing = Easing[easingName];
      if (isFunction !== undefined) {
        easing = easing();
      }
      const computed = sampleEasingFunction(Easing[modeName](easing));
      const samples = Samples[type];

      computed.forEach((value, key) => {
        expect(value).toBeCloseTo(samples[key], 2);
      });
    });
  });
});
